﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Configuration;
using System.Xml;

using ClientLib;

namespace JigsawAdmin
{
    public partial class Login : Form
    {
        string _encflag;
        string _enckeyfile;
        XmlDocument _keyfile;
        Dictionary<string, string> servers = new Dictionary<string, string>();

        ClientUtil _cutil;
        JsvcEnc.EncSoapXml xmlsvc;

        public Login()
        {
            InitializeComponent();

            try
            {
                _cutil = new ClientUtil();
                _keyfile = new XmlDocument();

                // store app.config values into variables
                txtKeyFile.Text = ConfigurationManager.AppSettings["KeyFile"].ToString();
                if (txtKeyFile.Text.Length > 0)
                {
                    ReadKeyFile(txtKeyFile.Text);
                    btnLoadFile.Enabled = true;
                }
            }
            catch (Exception ex)
            {
                ErrorUtil eutil = new ErrorUtil();
                eutil.LogException(_cutil.UserID, "Login Login", "", ex);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnBrowseKeyFile_Click(object sender, EventArgs e)
        {
            try
            {
                openFileDialog.Title = "Open KeyFile";
                openFileDialog.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*";
                openFileDialog.InitialDirectory = @"C:\";
                openFileDialog.DefaultExt = "txt";

                if (openFileDialog.ShowDialog() == DialogResult.OK)
                {
                    // show file selected
                    txtKeyFile.Text = openFileDialog.FileName;

                    // store file value to app.config as default location
                    WriteToAppConfig("KEYFILE", txtKeyFile.Text);

                    ReadKeyFile(txtKeyFile.Text);
                }
            }
            catch (Exception ex)
            {
                ErrorUtil eutil = new ErrorUtil();
                eutil.LogException(_cutil.UserID, "Login btnBrowseKeyFile_Click", "", ex);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="fileName"></param>
        private void ReadKeyFile(string fileName)
        {
            // read file, determine if encrypted
            System.IO.StreamReader sr = new System.IO.StreamReader(fileName);
            string keyfilestr = sr.ReadToEnd();
            sr.Close();

            XmlDocument xdoc = new XmlDocument();
            xdoc.LoadXml(keyfilestr);

            string encryptflag = xdoc.SelectSingleNode("keyfile/encrypted").InnerText;
            if (encryptflag.ToLower() == "true")
            {
                // enable passphrase textbox
                txtPassphrase.Enabled = true;
                _encflag = "true";
                _enckeyfile = xdoc.SelectSingleNode("keyfile/info").InnerText;
            }
            else
            {
                _encflag = "false";
                string tmpxml = "<info>" + xdoc.SelectSingleNode("keyfile/info").InnerXml + "</info>";
                _keyfile.LoadXml(tmpxml);
                btnLoadFile.Enabled = true;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void txtPassphrase_TextChanged(object sender, EventArgs e)
        {
            btnLoadFile.Enabled = true;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnLoadFile_Click(object sender, EventArgs e)
        {
            try
            {
                // if encyrpted, decrypt info section with passphrase
                if (_encflag == "true")
                {
                    EncryptUtil eutil = new EncryptUtil();
                    string symmkey = eutil.GetKeyFromPassphrase(txtPassphrase.Text);
                    string tmpxml = "<info>" + eutil.DecryptString2(_enckeyfile, symmkey) + "</info>";
                    _keyfile.LoadXml(tmpxml);
                }

                // parse the keyfile locations
                XmlNodeList parameters = _keyfile.SelectNodes("info/locations/location");
                if (parameters.Count > 0)
                {
                    // initialize server list combobox
                    servers[""] = " ";
                    foreach (XmlNode param in parameters)
                    {
                        string pname = param.SelectSingleNode("displayname").InnerText;
                        string pvalue = param.SelectSingleNode("serviceurl").InnerText;
                        if (!servers.ContainsKey(pname))
                        {
                            servers.Add(pname, pvalue);
                        }
                    }
                }

                cmbServerList.Enabled = true;
                cmbServerList.DataSource = new BindingSource(servers, null);
                cmbServerList.DisplayMember = "Key";
                cmbServerList.ValueMember = "Value";

                // parse the keyfile groupkeys
                //DataTable groupkeys = new DataTable();
                //groupkeys.Columns.Add("GroupName");
                //groupkeys.Columns.Add("GroupID");
                //groupkeys.Columns.Add("SymmKey");
            }
            catch (Exception ex)
            {
                ErrorUtil eutil = new ErrorUtil();
                eutil.LogException(_cutil.UserID, "Login btnLoadFile_Click", "", ex);
            }
        }

        /// <summary>
        /// When the user selects a server, attempt to connect to it and retrieve both
        /// the server time and RSA public key
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cmbServerList_SelectedIndexChanged(object sender, EventArgs e)
        {
            try
            {
                if (cmbServerList.SelectedIndex > 0)
                {
                    txtUserName.Text = "";
                    txtPassword.Text = "";

                    xmlsvc = new JsvcEnc.EncSoapXml();
                    xmlsvc.Url = cmbServerList.SelectedValue.ToString();
                    Cursor.Current = Cursors.WaitCursor;

                    // get server time and calculate offset
                    string svrtimestr = xmlsvc.GetServerTime();
                    
                    if (svrtimestr != null && svrtimestr != "")
                    {
                        string localtimestr = _cutil.GetTimeInMilliseconds();

                        double servermillisec = Convert.ToDouble(svrtimestr);
                        double localmillisec = Convert.ToDouble(localtimestr);

                        _cutil.Offset = localmillisec - servermillisec;
                        _cutil.ServiceURL = xmlsvc.Url;

                        // get public key, set value in clientutil instance
                        _cutil.PublicKey = xmlsvc.GetPublicKey();

                        // if successful, enable username and password fields
                        txtUserName.Enabled = true;
                        txtPassword.Enabled = true;
                        btnClear.Enabled = true;
                        
                        lblConnected.Text = "Connected";
                        lblConnected.ForeColor = Color.DarkGreen;

                        // get username and password if stored
                        txtUserName.Text = _keyfile.SelectSingleNode("info/username").InnerText;
                        txtPassword.Text = _keyfile.SelectSingleNode("info/password").InnerText;
                    }
                    else
                    {
                        lblConnected.Text = "Error: Unable to connect.";
                        lblConnected.ForeColor = Color.Maroon;
                    }

                    Cursor.Current = Cursors.Default;
                    Application.DoEvents();
                }
            }
            catch (Exception ex)
            {
                ErrorUtil eutil = new ErrorUtil();
                eutil.LogException(_cutil.UserID, "Login cmbServerList_SelectedIndexChanged", "", ex);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnClear_Click(object sender, EventArgs e)
        {
            //txtUserName.Text = "";
            //txtPassword.Text = "";
            Application.Exit();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnLogin_Click(object sender, EventArgs e)
        {
            try
            {
                if (txtUserName.Text.Length > 0 && txtPassword.Text.Length > 0)
                {
                    _cutil.UserName = txtUserName.Text;
                    _cutil.Password = txtPassword.Text;
                    EncryptUtil eutil = new EncryptUtil();

                    // form XML from input values, call service, decrypt and parse results
                    Dictionary<string, string> paramList = new Dictionary<string, string>();
                    string encryptedinput = _cutil.BuildMessageXML("SystemAdmin.UserLogin.Base", paramList, true);
                    string results = xmlsvc.Controller(_cutil.EncSymmKey, encryptedinput);
                    _cutil.ParseResponseMessage(eutil.DecryptString2(results, _cutil.SymmKey));

                    if (_cutil.ResponseCode == "Success")
                    {
                        // set sessionid and userid values
                        _cutil.SessionID = System.Guid.NewGuid().ToString();
                        _cutil.UserID = _cutil.Result;

                        Main frmMain = new Main(_cutil, cmbServerList.SelectedValue.ToString());
                        frmMain.FormClosed += new FormClosedEventHandler(Main_FormClosed);
                        frmMain.Show();
                        this.Hide();
                    }
                    else
                    {
                        // check for expired password
                        if (_cutil.Result == "Expired")
                        {
                            // show expired password form

                        }
                        else
                        {
                            MessageBox.Show(_cutil.Result, "Login Error");
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                ErrorUtil eutil = new ErrorUtil();
                eutil.LogException(_cutil.UserID, "Login btnLogin_Click", "", ex);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void txtPassword_TextChanged(object sender, EventArgs e)
        {
            btnClear.Enabled = true;
            btnLogin.Enabled = true;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Main_FormClosed(object sender, FormClosedEventArgs e)
        {
            this.Close();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        private void WriteToAppConfig(string key, string value)
        {
            System.Configuration.Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
            config.AppSettings.Settings.Remove(key.ToUpper());
            config.AppSettings.Settings.Add(key.ToUpper(), value);
            config.Save(ConfigurationSaveMode.Modified);
            ConfigurationManager.RefreshSection("AppSettings");
        }
    }
}
